package com.fast.develop.meta.dm.loader;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.EnumUtil;
import com.fast.develop.meta.base.loader.MetaLoader;
import com.fast.develop.meta.dm.MetaDomainModel;
import com.fast.develop.meta.dm.MetaField;
import com.fast.develop.meta.dm.builder.MetaModelBuilder;
import com.fast.develop.meta.dm.extend.ExtendStrategy;
import org.everit.json.schema.ObjectSchema;
import org.everit.json.schema.loader.SchemaClient;
import org.everit.json.schema.loader.SchemaLoader;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author 莫寅
 * @createTime 2022-06-04 13:31
 * @desc：
 */
public class MetaModelLoader implements MetaLoader<MetaDomainModel> {

    public static final String SCHEMA_PATH = "/.&&schema/domain/v1.0/domain.json";

    private MetaFieldLoader metaFieldLoader = new MetaFieldLoader();


    private ObjectSchema objectSchema;


    public MetaModelLoader() {
        this.objectSchema = (ObjectSchema) SchemaLoader.builder()
                .schemaClient(SchemaClient.classPathAwareClient())
                .schemaJson(
                        new JSONObject(new JSONTokener(IoUtil.readUtf8(getClass().getResourceAsStream(
                                SCHEMA_PATH)))))
                .build().load().build();
    }

    public MetaModelLoader(ObjectSchema objectSchema) {
        this.objectSchema = objectSchema;
    }

    @Override
    public void validation(JSONObject rawSchema){
        objectSchema.validate(rawSchema);
    }

    @Override
    public MetaDomainModel load(JSONObject rawSchema){
        //检验json
        validation(rawSchema);

        MetaModelBuilder MetaModelBuilder = new MetaModelBuilder();

        bindName(rawSchema, MetaModelBuilder);
        bindTableName(rawSchema, MetaModelBuilder);
        bindComment(rawSchema, MetaModelBuilder);
        bindPmodelId(rawSchema, MetaModelBuilder);
        bindExtendStrategy(rawSchema, MetaModelBuilder);
        bindFieldsAndPrimaryField(rawSchema, MetaModelBuilder);


        MetaDomainModel metaDomainModel = new MetaDomainModel(MetaModelBuilder);
        return metaDomainModel;
    }


    private void bindName(JSONObject rawSchema, MetaModelBuilder MetaModelBuilder){
        MetaModelBuilder.setName(rawSchema.optString("name"));
    }

    private void bindTableName(JSONObject rawSchema, MetaModelBuilder MetaModelBuilder){
        MetaModelBuilder.setTableName(rawSchema.optString("tableName"));
    }

    private void bindComment(JSONObject rawSchema, MetaModelBuilder MetaModelBuilder){
        MetaModelBuilder.setComment(rawSchema.optString("comment"));
    }

    private void bindPmodelId(JSONObject rawSchema, MetaModelBuilder MetaModelBuilder){
        MetaModelBuilder.setSuperModel(rawSchema.optString("superModel"));
    }


    private void bindExtendStrategy(JSONObject rawSchema, MetaModelBuilder MetaModelBuilder){
        JSONObject value = rawSchema.optJSONObject("extendStrategy");
        if(Objects.nonNull(value)){
            Boolean isExtend = value.optBoolean("isExtend");
            Boolean isAbstract = value.optBoolean("isAbstract");
            String strategy = value.optString("strategy");
            ExtendStrategy.Strategy strateg = EnumUtil.fromString(ExtendStrategy.Strategy.class, strategy, null);


            ExtendStrategy extendStrategy = new ExtendStrategy();

            extendStrategy.setExtend(isExtend);
            extendStrategy.setAbstract(isAbstract);
            extendStrategy.setStrategy(strateg);

            MetaModelBuilder.setExtendStrategy(extendStrategy);
        }
    }



    private void bindFieldsAndPrimaryField(JSONObject rawSchema, MetaModelBuilder MetaModelBuilder){
        JSONArray fields = rawSchema.optJSONArray("fields");

        if(Objects.nonNull(fields)){
            List<MetaField> metaFields = new ArrayList<>();

            fields.forEach(field -> {
                MetaField metaField = metaFieldLoader.load((JSONObject) field);

                //在模型中设置主键
                if(metaField.getPrimaryKey()){
                    MetaModelBuilder.setIdentifierProperty(metaField);
                }
                metaFields.add(metaField);
            });

            MetaModelBuilder.setFields(metaFields);
        }
    }

    public ObjectSchema getObjectSchema() {
        return objectSchema;
    }

}
